#include "control.h"
#include <iostream>

Control::Control(
	GLFWwindow *window,
	std::shared_ptr<Camera> camera,
	std::shared_ptr<Object> center,
	const float radius) : window(window),
						  camera(camera),
						  center(center),
						  radius(radius)
{
	glfwGetCursorPos(window, &x_pre, &y_pre);
	glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
}

void Control::update()
{
	bool should_move = false;
	bool crashed = false;
	glm::vec2 move_direction(0, 0);
	if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
	{
		should_move = true;
		move_direction.x = 1;
	}
	if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
	{
		should_move = true;
		crashed = crashed | move_direction.x != 0;
		move_direction.x = -1;
	}
	if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
	{
		should_move = true;
		move_direction.y = 1;
	}
	if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
	{
		should_move = true;
		crashed = crashed | move_direction.y != 0;
		move_direction.y = -1;
	}
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
	{
		glfwSetWindowShouldClose(window, GLFW_TRUE);
	}
	double xpos, ypos, x_dif, y_dif;
	glfwGetCursorPos(window, &xpos, &ypos);
	x_dif = xpos - x_pre;
	y_dif = ypos - y_pre;
	x_pre = xpos;
	y_pre = ypos;
	turn(
		glm::radians(-180 * float(asin(y_dif / VIEW_RADIUS))),
		glm::radians(-180 * float(asin(x_dif / VIEW_RADIUS)))
	);
	// turn(0.01, 0.01);
	if(should_move && !crashed) {
		move(move_direction);
	}
	update_camera();
}

void Control::turn(float delta_pitch, float delta_yaw)
{
	// 全局视角旋转
	auto &z_axis = center_to_camera;
	// 先水平旋转
	view_direction = rotate_vector(view_direction, z_axis, delta_yaw);
	// 再根据垂直旋转改变倾角
	float pitch = glm::acos(glm::dot(
		view_direction,
		z_axis
	));
	if(pitch - delta_pitch <= THRESHOLD)
	{
		delta_pitch = pitch - THRESHOLD;
	}
	if(pitch - delta_pitch >= PI - THRESHOLD)
	{
		delta_pitch = pitch - (PI - THRESHOLD);
	}
	auto x_axis = glm::normalize(glm::cross(
		view_direction,
		z_axis
	));
	view_direction = rotate_vector(view_direction, x_axis, delta_pitch);
	view_direction = glm::normalize(view_direction);
}

void Control::move(glm::vec2 move_direction)
{
	// 移动的时候要修改视角方向，其实就是绕某个轴旋转
	// 局部坐标系
	auto &z_axis = center_to_camera;
	auto x_axis = glm::normalize(glm::cross(
		view_direction,
		z_axis
	));
	// 先前后
	view_direction = rotate_vector(view_direction, x_axis, -speed * move_direction.x);
	center_to_camera = rotate_vector(center_to_camera, x_axis, -speed * move_direction.x);
	// 后左右
	auto y_axis = glm::cross(
		z_axis,
		x_axis
	);
	view_direction = rotate_vector(view_direction, y_axis, -speed * move_direction.y);
	center_to_camera = rotate_vector(center_to_camera, y_axis, -speed * move_direction.y);
	view_direction = glm::normalize(view_direction);
	center_to_camera = glm::normalize(center_to_camera);
}

void Control::update_camera()
{
	// 设置位置
	camera->setPosition(get_view_position());
	// auto aim = camera->getPosition();
	// std::cout << aim.x << ' ' << aim.y << ' ' << aim.z << std::endl;
	// 设置方向
	camera->aimAt(camera->getPosition() + view_direction, center_to_camera);
}

glm::vec3 Control::get_view_position() const
{
	auto center_position = center->getPosition();
	auto c2c = center_to_camera * radius;
	return center_position + c2c;
}

glm::vec3 rotate_vector(glm::vec3 v, glm::vec3 n, float t)
{
	// 向量绕任意轴旋转的方法：https://www.zhihu.com/question/488858855
	float cost = glm::cos(t);
	float sint = glm::sin(t);
	float dot = glm::dot(n, v);
	glm::vec3 cross = glm::cross(n, v);
	return cost * v + (1 - cost) * dot * n + sint * cross;
}